<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>KeyAuth WebSocket 测试工具</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <div class="header">
            <img src="logo.png" alt="KeyAuth Logo" class="logo">
            <h1>KeyAuth WebSocket 测试工具</h1>
        </div>
        <div class="status">
            <div id="statusIndicator" class="status-indicator"></div>
            <span id="statusText">未连接</span>
            <input type="text" id="wsUrl" value="ws://127.0.0.1:9876" style="margin-left:20px;width:260px;" />
            <button id="connectBtn">连接</button>
            <button id="disconnectBtn" disabled>断开</button>
        </div>
        <div class="main-layout">
            <div class="sidebar">
                <div class="action-group">
                    <h2>连接与授权</h2>
                    <ul class="action-list">
                        <li><button class="action-btn" data-action="Connect">Connect</button></li>
                        <li><button class="action-btn" data-action="Ping">Ping</button></li>
                    </ul>
                </div>
                <div class="action-group">
                    <h2>密钥使用</h2>
                    <ul class="action-list">
                        <li><button class="action-btn" data-action="SignData">SignData</button></li>
                        <li><button class="action-btn" data-action="VerifyData">VerifyData</button></li>
                    </ul>
                </div>
                <div class="action-group">
                    <h2>DID身份管理</h2>
                    <ul class="action-list">
                        <li><button class="action-btn" data-action="CreateSignedDID">CreateSignedDID</button></li>
                        <li><button class="action-btn" data-action="VerifyDID">VerifyDID</button></li>
                    </ul>
                </div>
                <div class="action-group">
                    <h2>区块链合约操作</h2>
                    <ul class="action-list">
                        <li><button class="action-btn" data-action="Invoke">Invoke</button></li>
                        <li><button class="action-btn" data-action="Query">Query</button></li>
                    </ul>
                </div>
            </div>
            <div class="content-area">
                <div class="section-title">请求参数</div>
                <div class="param-toolbar">
                    <button class="copy-btn" id="copyParamsBtn">复制参数</button>
                    <button class="restore-btn" id="restoreParamsBtn">恢复模板</button>
                </div>
                <textarea id="params" style="width:100%;min-height:120px;"></textarea>
                <div class="form-group">
                    <button id="sendBtn" disabled>发送请求</button>
                </div>
                <div class="section-title">响应结果</div>
                <div class="response-toolbar">
                    <button class="copy-btn" id="copyRespBtn">复制响应</button>
                </div>
                <div id="responseContainer" class="json-view" style="display: none;"><pre id="response"></pre></div>
            </div>
        </div>
    </div>
    <script src="keyauth-ws-sdk.js"></script>
    <script>
    // 典型参数模板
    const paramTemplates = {
        Connect: {
            app_info: {
                app_name: "测试应用",
                app_id: "test-app-" + Date.now(),
                app_version: "1.0.0",
                developer: "开发者公司",
                icon_url: "https://example.com/icon.png",
                description: "这是一个用于测试的应用"
            },
            scopes: ["sign", "verify", "did", "contract"]
        },
        Ping: {},
        SignData: { 
            header: {
                alg: "SM2",
                timestamp: Date.now(),
                nonce: "random-" + Math.floor(Math.random() * 1000000),
                method: "POST",
                path: "/api/products"
            },
            payload: {
                name: "新商品",
                price: 99.99,
                description: "这是一个示例商品描述"
            }
        },
        VerifyData: { 
            header: {
                alg: "SM2",
                timestamp: Date.now(),
                nonce: "random-" + Math.floor(Math.random() * 1000000),
                method: "POST",
                path: "/api/products"
            },
            payload: {
                name: "新商品",
                price: 99.99,
                description: "这是一个示例商品描述"
            },
            signature: "...",
            publicKey: "-----BEGIN PUBLIC KEY-----\nXXXXX\n-----END PUBLIC KEY-----"
        },
        CreateSignedDID: { 
            didInfo: { 
                name: "Alice", 
                organization: "Example Org" 
            } 
        },
        VerifyDID: { 
            // 现在接受JWT格式的didDocument
            didDocument: "eyJ0eXAiOiJKV1QrRElEIiwiYWxnIjoiU00yIiwia2lkIjoiZGlkOmtleWF1dGg6YWJjZGVmMTIzNDU2I2tleXMtMSJ9.eyJpYXQiOjE3MDY4NDcxMjMsIkBjb250ZXh0IjoiaHR0cHM6Ly93d3cudzMub3JnL25zL2RpZC92MSIsImlkIjoiZGlkOmtleWF1dGg6YWJjZGVmMTIzNDU2IiwiY3JlYXRlZCI6IjIwMjQtMDItMDFUMTA6NDA6MDAuMDAwMDAwMFoiLCJwdWJsaWNLZXkiOlt7ImlkIjoiI2tleXMtMSIsInR5cGUiOiJTTTJWZXJpZmljYXRpb25LZXkyMDE5IiwiY29udHJvbGxlciI6ImRpZDprZXlhdXRoOmFiY2RlZjEyMzQ1NiIsInB1YmxpY0tleVBlbSI6Ii0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG4uLi5cbi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLSJ9XSwiZGlkSW5mbyI6eyJuYW1lIjoiQWxpY2UiLCJvcmdhbml6YXRpb24iOiJFeGFtcGxlIE9yZyJ9fQ.SIGNATURE"
        },
        Invoke: {
            chainID: "chain1",
            nodeAddr: "127.0.0.1",
            nodePort: 8080,
            contract: "example_contract",
            method: "transfer",
            params: {
                from: "account1",
                to: "account2",
                amount: "100",
                token: "EXM"
            }
        },
        Query: {
            chainID: "chain1",
            nodeAddr: "127.0.0.1",
            nodePort: 8080,
            contract: "example_contract",
            method: "getBalance",
            params: {
                account: "account1",
                token: "EXM"
            }
        }
    };
    let wsClient = null;
    let currentAction = "Connect"; // 默认选择Connect操作
    let lastCreatedDID = null; // 存储最近创建的DID文档
    let lastSignedPayload = null; // 存储最近签名的payload和signature
    // 连接管理
    const connectBtn = document.getElementById('connectBtn');
    const disconnectBtn = document.getElementById('disconnectBtn');
    const statusIndicator = document.getElementById('statusIndicator');
    const statusText = document.getElementById('statusText');
    const wsUrlInput = document.getElementById('wsUrl');
    // action选择
    const actionBtns = document.querySelectorAll('.action-btn');
    // 参数区
    const paramsTextarea = document.getElementById('params');
    const copyParamsBtn = document.getElementById('copyParamsBtn');
    const restoreParamsBtn = document.getElementById('restoreParamsBtn');
    // 发送
    const sendBtn = document.getElementById('sendBtn');
    // 响应区
    const responseContainer = document.getElementById('responseContainer');
    const responseElement = document.getElementById('response');
    const copyRespBtn = document.getElementById('copyRespBtn');

    // action切换
    actionBtns.forEach(btn => {
        btn.addEventListener('click', async () => {
            actionBtns.forEach(b => b.classList.remove('selected'));
            btn.classList.add('selected');
            currentAction = btn.dataset.action;
            
            // 优先显示最近生成的DID文档（现在是JWT字符串）
            if (currentAction === 'VerifyDID' && window.lastCreatedDID) {
                paramsTextarea.value = JSON.stringify({ didDocument: window.lastCreatedDID }, null, 2);
            } 
            // 优先显示最近签名的payload和signature
            else if (currentAction === 'VerifyData') {
                if (lastSignedPayload) {
                    paramsTextarea.value = JSON.stringify(lastSignedPayload, null, 2);
                } else {
                    // 如果没有最近签名的数据，则尝试从连接信息中获取公钥
                    const template = JSON.parse(JSON.stringify(paramTemplates[currentAction]));
                    
                    if (wsClient && wsClient.sessionToken) {
                        // 使用辅助函数获取公钥
                        template.publicKey = getPublicKeyFromSDK();
                    }
                    
                    paramsTextarea.value = JSON.stringify(template, null, 2);
                }
            }
            else {
                updateParamsTemplate();
            }
        });
    });

    function updateParamsTemplate() {
        // VerifyDID优先显示最近生成的DID文档（JWT字符串）
        if (currentAction === 'VerifyDID' && window.lastCreatedDID) {
            paramsTextarea.value = JSON.stringify({ didDocument: window.lastCreatedDID }, null, 2);
            return;
        }
        // VerifyData优先显示最近签名的payload和signature
        if (currentAction === 'VerifyData') {
            if (lastSignedPayload) {
                paramsTextarea.value = JSON.stringify(lastSignedPayload, null, 2);
                return;
            } else if (wsClient && wsClient.sessionToken) {
                // 如果没有最近签名的数据，则尝试从连接信息中获取公钥
                const template = JSON.parse(JSON.stringify(paramTemplates[currentAction]));
                
                // 使用辅助函数获取公钥
                template.publicKey = getPublicKeyFromSDK();
                
                paramsTextarea.value = JSON.stringify(template, null, 2);
                return;
            }
        }
        const tpl = paramTemplates[currentAction] || {};
        paramsTextarea.value = JSON.stringify(tpl, null, 2);
    }
    // 辅助函数：从 SDK 获取公钥
    function getPublicKeyFromSDK() {
        if (!wsClient) return "请先连接服务器";
        
        try {
            // 只从 SDK 的 connectionInfo 属性获取
            if (wsClient.connectionInfo) {
                console.log('从 SDK 属性获取连接信息:', wsClient.connectionInfo);
                
                if (wsClient.connectionInfo.authorized_keys && wsClient.connectionInfo.authorized_keys.length > 0) {
                    const publicKey = wsClient.connectionInfo.authorized_keys[0].public_key;
                    console.log('从 SDK connectionInfo.authorized_keys 找到公钥:', publicKey);
                    return publicKey;
                }
            }
            
            return "未找到公钥";
        } catch (e) {
            console.error('获取公钥失败:', e);
            return "获取公钥失败";
        }
    }
    
    // 初始化默认action
    document.querySelector('[data-action="Connect"]').click(); // 默认选择Connect操作

    // 复制参数
    copyParamsBtn.onclick = () => {
        navigator.clipboard.writeText(paramsTextarea.value);
    };
    // 恢复模板
    restoreParamsBtn.onclick = () => updateParamsTemplate();
    // 复制响应
    copyRespBtn.onclick = () => {
        navigator.clipboard.writeText(responseElement.textContent);
    };

    // 连接
    connectBtn.onclick = () => {
        console.log('开始连接到WebSocket服务器:', wsUrlInput.value);
        statusText.textContent = '正在连接...';
        
        wsClient = new KeyAuthWS(wsUrlInput.value);
        
        // 创建默认应用信息
        const appInfo = {
            app_name: "KeyAuth测试工具",
            app_id: "test-app-" + Date.now(),
            app_version: "1.0.0",
            developer: "KeyAuth团队",
            icon_url: "logo.png",
            description: "KeyAuth WebSocket 测试工具",
            scopes: ["sign", "verify", "did", "contract"]
        };
        
        console.log('应用信息:', appInfo);
        
        // 添加更多事件监听器以便调试
        wsClient.on('open', () => {
            console.log('WebSocket连接已建立，等待发送Connect请求...');
            statusText.textContent = 'WebSocket已连接，正在进行应用认证...';
        });
        
        wsClient.on('message', (msg) => {
            console.log('收到WebSocket消息:', msg);
        });
        
        wsClient.connect(appInfo).then((response) => {
            console.log('Connect请求成功:', response);
            if (response && response.status === 'success' && response.data) {
                wsClient.connectionInfo = response.data;
                wsClient.sessionToken = response.data.session_token;
                wsClient._saveConnectionInfoToStorage();
            }
            statusIndicator.classList.add('connected');
            statusText.textContent = '已连接并完成应用认证';
            connectBtn.disabled = true;
            disconnectBtn.disabled = false;
            sendBtn.disabled = false;
            responseElement.textContent = JSON.stringify(response, null, 2);
            responseContainer.style.display = 'block';
            // 默认选择Connect操作
            document.querySelector('[data-action="Connect"]').click();
        }).catch((error) => {
            console.error('Connect请求失败:', error);
            statusText.textContent = '连接失败: ' + (error.message || '未知错误');
            responseElement.textContent = '连接失败: ' + (error.message || '未知错误');
            responseContainer.style.display = 'block';
        });
        
        wsClient.on('close', (e) => {
            console.log('WebSocket连接已关闭:', e);
            statusIndicator.classList.remove('connected');
            statusText.textContent = '连接已关闭';
            connectBtn.disabled = false;
            disconnectBtn.disabled = true;
            sendBtn.disabled = true;
        });
        wsClient.on('error', (e) => {
            console.error('WebSocket连接错误:', e);
            statusText.textContent = '连接错误';
        });
    };
    // 断开
    disconnectBtn.onclick = () => {
        if (wsClient) wsClient.disconnect();
    };
    // 发送请求
    sendBtn.onclick = async () => {
        if (!wsClient) {
            alert('请先连接到WebSocket服务器');
            return;
        }
        let params;
        try {
            params = JSON.parse(paramsTextarea.value);
        } catch (e) {
            alert('参数格式错误，请检查JSON');
            return;
        }

        try {
            // 使用内部 _send 方法发送请求
            const resp = await wsClient._send(currentAction, params, null, 
                currentAction !== 'Connect' ? {
                    appName: "KeyAuth测试工具",
                    developer: "KeyAuth团队",
                    iconUrl: "logo.png"
                } : null // 对于Connect请求，不额外添加client_info，因为它在params里
            );
            responseElement.textContent = JSON.stringify(resp, null, 2);
            responseContainer.style.display = 'block';
            
            // 如果是Connect请求且成功，打印连接信息
            if (currentAction === 'Connect' && resp.status === 'success') {
                console.log('调试 - Connect 响应:', resp);
                // 等待一会儿，确保SDK已经处理了连接信息
                setTimeout(() => {
                    console.log('调试 - Connect 后的 wsClient:', wsClient);
                    console.log('调试 - Connect 后的 connectionInfo:', wsClient.connectionInfo);
                    if (wsClient.connectionInfo && wsClient.connectionInfo.authorized_keys) {
                        console.log('调试 - Connect 后的 authorized_keys:', wsClient.connectionInfo.authorized_keys);
                    }
                }, 500);
            }
            
            // 如果是CreateSignedDID请求且成功，自动将didDocument填入到VerifyDID的参数中
            if (currentAction === 'CreateSignedDID' && resp.data && resp.data.didDocument) {
                // 保存didDocument到全局变量，用于后续VerifyDID使用（现在是JWT字符串）
                window.lastCreatedDID = resp.data.didDocument;
                // 更新VerifyDID的参数模板
                paramTemplates.VerifyDID = {
                    didDocument: resp.data.didDocument
                };
                if (confirm('DID文档创建成功！是否立即进行验证？')) {
                    currentAction = 'VerifyDID';
                    actionBtns.forEach(b => b.classList.remove('selected'));
                    document.querySelector('[data-action="VerifyDID"]').classList.add('selected');
                    paramsTextarea.value = JSON.stringify({ didDocument: resp.data.didDocument }, null, 2);
                }
            }
            
            // 如果是SignData请求且成功，自动将header、payload和signature填入到VerifyData的参数中
            if (currentAction === 'SignData' && resp.data && resp.data.signature) {
                // 获取原始header和payload
                let originalHeader, originalPayload;
                try {
                    const params = JSON.parse(paramsTextarea.value);
                    originalHeader = params.header;
                    originalPayload = params.payload;
                } catch (e) {
                    console.error('解析原始参数失败', e);
                    return;
                }
                
                // 调试：打印连接信息
                console.log('调试 - wsClient:', wsClient);
                console.log('调试 - connectionInfo:', wsClient.connectionInfo);
                if (wsClient.connectionInfo && wsClient.connectionInfo.authorized_keys) {
                    console.log('调试 - authorized_keys:', wsClient.connectionInfo.authorized_keys);
                }
                
                // 从连接信息获取公钥
                const publicKey = getPublicKeyFromSDK();
                console.log('调试 - 获取到的公钥:', publicKey);
                
                // 保存header、payload和signature到全局变量
                lastSignedPayload = {
                    header: originalHeader,
                    payload: originalPayload,
                    signature: resp.data.signature,
                    publicKey: publicKey
                };
                
                console.log('调试 - lastSignedPayload:', lastSignedPayload);

                // 更新VerifyData的参数模板
                paramTemplates.VerifyData = lastSignedPayload;

                if (confirm('签名成功！是否立即进行验证？')) {
                    currentAction = 'VerifyData';
                    actionBtns.forEach(b => b.classList.remove('selected'));
                    document.querySelector('[data-action="VerifyData"]').classList.add('selected');
                    paramsTextarea.value = JSON.stringify(lastSignedPayload, null, 2);
                }
            }
        } catch (e) {
            responseElement.textContent = '请求失败: ' + e.message;
            responseContainer.style.display = 'block';
        }
    };
    </script>
</body>
</html> 